package org.managarm.jmanaintlib.runtime.system;

import org.managarm.jmanaintlib.machine.VmError;
import org.managarm.jmanaintlib.machine.VmState;
import org.managarm.jmanaintlib.machine.VmCell;
import org.managarm.jmanaintlib.machine.VmExecutor;
import org.managarm.jmanaintlib.machine.VmCode;
import org.managarm.jmanaintlib.machine.VmMachine;
import org.managarm.jmanavalib.core.VaMthInfo;

public class RtThread {
	public static final int STATE_NONE = 0;
	public static final int STATE_FINISHED = 1;
	public static final int STATE_SUSPENDED = 2;
	public static final int STATE_ACTIVE = 3;
	public static final int STATE_WAITING = 4;
	
	private class NativeThread extends Thread {
		@Override public void run() {
			ourInstance.setCurrentThread(threadIdnum);
			
			try {
				final RtProcess process
						= (RtProcess)ourInstance.objectRequest(processIdnum);
				final VmMachine machine = process.getMachine();
				
				// initialize the virtual machine state
				final VmState machine_state = new VmState();
				if((mthInfo.flags0 & VaMthInfo.FLAG0_STATIC) != 0) {
					final VmCode code = machine.getCode(mthInfo);
					machine_state.pushMethod(code.invoke());
				}else{
					final VmCode code = machine.findMethod(mthInfo,
							objectCell.getClsInfo());
					final VmExecutor executor = code.invoke();
					executor.pushArgument(objectCell);
					machine_state.pushMethod(executor);
				}
				
				currentState = STATE_SUSPENDED;
				while(machine_state.finished() == false) {
					// read the current thread state
					final int state = currentState();
					
					// execute a single instruction or sleep
					// depending on the current thread state
					if(state == STATE_FINISHED) {
						return;
					}else if(state == STATE_ACTIVE
							|| state == STATE_WAITING) {
						machine_state.singleStep();
					}else if(state == STATE_SUSPENDED) {
						try { sleep(16); } catch(InterruptedException e) { }
					}else{
						System.err.println("Illegal thread state");
					}
				}
				currentState = STATE_FINISHED;
			} catch(VmError e) {
				e.printStackTrace();
			}
		}
	}
	
	private final RtInstance ourInstance;
	// thread and process object numbers
	private long threadIdnum;
	private final long processIdnum;
	// class, method and object of the main method
	private final VaMthInfo mthInfo;
	private final VmCell objectCell;
	// native thread that processes this virtual machine thread
	private final NativeThread nativeThread;
	// current virtual machine thread state
	private volatile int currentState = STATE_NONE;
	
	public RtThread(RtInstance instance, long process,
			VaMthInfo mthinfo, VmCell object) {
		ourInstance = instance;
		processIdnum = process;
		
		// store object, method and class information
		mthInfo = mthinfo; objectCell = object;
		
		// start the executor, wait until everything is initialized
		nativeThread = new NativeThread();
	}
	
	public void execute(long objectid) {
		this.threadIdnum = objectid;
		
		nativeThread.start();
		while(currentState == STATE_NONE)
			Thread.yield();
	}
	
	public long getProcess() {
		return processIdnum;
	}
	
	// returns the current thread state
	public int currentState() {
		return currentState;
	}
	
	// changes the current thread state
	public void enterState(int state) {
		enterState(state, STATE_NONE);
	}
	public void enterState(int state, int condition) {
		synchronized(this) { // ensure that this operation is atomic
			// check the current thread state
			final int curstate = currentState;
			if(condition != STATE_NONE && curstate != condition)
				return;
			
			currentState = state; // change the current state
			if(curstate == STATE_SUSPENDED)
				nativeThread.interrupt(); // interrupt the executor thread
			// in order to let it continue it's operation
		}
	}
}
